﻿using System;
using System.Collections.Generic;
using System.Linq;
using HK.Core.Extend;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Core.Load.Protocol.Data;
using HK.Core.Pool;
using HK.Core.Utils;
using HK.Editor.Common;
using HK.Editor.GUIEx.Data;
using HK.Editor.GUIEx.Styles;
using HK.Editor.GUIEx.TreeView.Control;
using HK.Editor.GUIEx.Window;
using HK.Editor.Load.Data;
using HK.Editor.Load.Protocol.Window;
using HK.Editor.Utils;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;

namespace HK.Editor.Load.Window
{
    /// <summary>
    /// 加载监视窗体
    /// </summary>
    public class LoadWatchWindow : MultiColsWindow<LoadWatchWindow, WindowConf, LoadTree, LoadBranch>, ILoadWatchWindow<LoadWatchWindow, LoadTree, LoadBranch>
    {
        
#region Menu

        /// <summary>
        /// 显示宏定义窗口.
        /// </summary>
        [MenuItem(EditorConst.MENU_TXT_TOOL__LOAD_WATCH_WIN, false, EditorConst.MENU_PRIORITY_TOOL_LOAD_WATCH_WIN)]
        static void ShowWindow()
        {
            var conf = WindowConf.Create("加载监视", new Rect(0, 0, 1600, 600), (int)GUIOperateOptions.LoadWatchWindow);
            // 显示窗体
            ShowWindow(conf, true, true);
        }

#endregion

#region Rect

        private static readonly float NoWidth = 30.0f;
        private static readonly float AssetKeyWidth = 200.0f;

#endregion

#region Data

		protected override bool InitData()
		{
			if (!base.InitData()) return false;
            
            // 绑定事件
            UtilsLoad.EntityNotify += EntityNotifyEvent;
            UtilsLoad.AssetNotify += AssetNotifyEvent;
		
			ObjectPool<LoadBranch>.Generate(100, true, 0.2f);
			
			var testBranch1 = ObjectPool<LoadBranch>.Pop();
			testBranch1.AssetKey = "Assets/AAA/BBB.png";
			testBranch1.Caller = "Assets/AAA/BBB(R:02)";
			testBranch1.Size = 5656565;
			testBranch1.MemorySize = 5456565;
			testBranch1.Async = false;
			Data.AddBranch(testBranch1);
            
			var testBranch2 = ObjectPool<LoadBranch>.Pop();
			testBranch2.AssetKey = "Assets/CCC/DDD.spriteatlas";
			testBranch2.Caller = "Assets/CCC/DDD(R:01)";
			testBranch2.Async = true;
			testBranch2.Size = 12313141;
			testBranch2.MemorySize = 11313141;
			Data.AddBranch(testBranch2);
            
			var testBranch3 = ObjectPool<LoadBranch>.Pop();
			testBranch3.AssetKey = "Assets/CCC/DDD.spriteatlas";
			testBranch3.Caller = "Assets/CCC/DDD(R:02)";
			testBranch3.MemorySize = 11313141;
			testBranch3.Async = true;
			Data.AddBranch(testBranch3);
            
			var testBranch4 = ObjectPool<LoadBranch>.Pop();
			testBranch4.AssetKey = "Assets/CCC/DDD.spriteatlas";
			testBranch4.Caller = "Assets/CCC/DDD(R:03)";
			testBranch4.MemorySize = 11213041;
			testBranch4.Async = false;
			Data.AddBranch(testBranch4);
            
			var testBranch5 = ObjectPool<LoadBranch>.Pop();
			testBranch5.AssetKey = "Assets/CCC/EEE.prefab";
			testBranch5.Caller = "Assets/CCC/EEE(R:01)";
			testBranch5.Async = true;
			testBranch5.Size = 82313141;
			testBranch5.MemorySize = 81313141;
			Data.AddBranch(testBranch5);
            
			var testBranch6 = ObjectPool<LoadBranch>.Pop();
			testBranch6.AssetKey = "Assets/CCC/EEE.prefab";
			testBranch6.Caller = "Assets/CCC/DDD(R:03)";
			testBranch6.MemorySize = 11213041;
			testBranch6.Async = false;
			Data.AddBranch(testBranch6);
			
			return true;
		}

#endregion

#region Events

		/// <summary>
		/// 加载通知事件 : Asset
		/// </summary>
		/// <param name="iEvent">Event</param>
		/// <param name="iAssetInfo">Asset加载信息</param>
		private void AssetNotifyEvent(NotifyLoadEvent iEvent, IAssetInfo iAssetInfo)
		{
			switch (iEvent)
			{
				case NotifyLoadEvent.Add:      // 追加
					break;
				case NotifyLoadEvent.Remove:   // 移除
					break;
				case NotifyLoadEvent.Refresh:  // 刷新
					break;
			}
		}
		
		/// <summary>
		/// 加载通知事件 : Entity
		/// </summary>
		/// <param name="iEvent">Event</param>
		/// <param name="iEntityInfo">Entity加载信息</param>
		private void EntityNotifyEvent(NotifyLoadEvent iEvent, IEntityInfo iEntityInfo)
		{
			switch (iEvent)
			{
				case NotifyLoadEvent.Add:      // 追加
					break;
				case NotifyLoadEvent.Remove:   // 移除
					break;
				case NotifyLoadEvent.Refresh:  // 刷新
					break;
			}
		}

		/// <summary>
		/// 窗体关闭回调
		/// </summary>
		protected override void OnWindowClosed()
		{
			base.OnWindowClosed();
			
			// 撤销绑定事件
			UtilsLoad.EntityNotify -= EntityNotifyEvent;
			UtilsLoad.AssetNotify -= AssetNotifyEvent;
		}

#endregion

#region TableTree
        
        /// <summary>
        /// 树枝列表
        /// </summary>
        protected override IList<LoadBranch> Branches => Data.Branches;

        /// <summary>
        /// 列数
        /// </summary>
        protected override int ColumnsCount => Enum.GetValues(typeof(LoadTreeColumns)).Length;
        
        /// <summary>
        /// 折叠箭头所在列索引
        /// </summary>
        protected override int FoldoutColIndex => 1;
        
        /// <summary>
        /// 生成树枝列表
        /// </summary>
        /// <param name="iRoot">根节点</param>
        /// <returns>树枝列表</returns>
        protected override IList<LoadBranch> GenerateTreeBranches(LoadBranch iRoot)
        {
	        if (null == iRoot) return null;
	        var branches = new List<LoadBranch> { iRoot };
	        if (!iRoot.Valid) return branches;
            
	        if (null != Branches && 0 < Branches.Count)
	        {
		        branches.AddRange(Branches);
	        }
			
	        // 重新排序
	        branches = branches
		        .OrderBy(iO => iO.AssetKey)
		        .ThenBy(iO => iO.Depth)
		        .ThenBy(iO => iO.IsCaller ? iO.Caller : iO.AssetKey)
		        .ToList();
	        return branches;
        }

        /// <summary>
        /// 生成表头
        /// </summary>
        /// <param name="iWidth">TableView宽度</param>
        /// <returns>表头</returns>
        protected override MultiColumnHeaderState GenerateTableHeader(float iWidth)
        {
            var assetWidth = iWidth * 0.3f;
            assetWidth = AssetKeyWidth >= assetWidth ? AssetKeyWidth : assetWidth;
            var widthTmp = (iWidth - NoWidth - assetWidth) / 9.0f;
            
			var columns = new[] 
			{
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("No"),
					contextMenuText = "No",
					headerTextAlignment = TextAlignment.Center,
					canSort = false,
					//sortedAscending = true,
					//sortingArrowAlignment = TextAlignment.Right,
					width = NoWidth, 
					minWidth = NoWidth * 0.6f,
					maxWidth = NoWidth * 2.0f,
					autoResize = false,
					allowToggleVisibility = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("Asset"),
					headerTextAlignment = TextAlignment.Left,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = assetWidth, 
					minWidth = assetWidth * 0.6f,
					maxWidth = assetWidth * 1.5f,
					autoResize = false,
					allowToggleVisibility = false
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("Asset Type"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("后缀"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true,
					allowToggleVisibility = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("From"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("异步"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("引用数"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("大小"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("运存"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("耗时"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("创建"),
					headerTextAlignment = TextAlignment.Center,
					canSort = true,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = widthTmp,
					minWidth = widthTmp * 0.6f,
					maxWidth = widthTmp * 1.5f,
					autoResize = true
				}
			};
            
			var state =  new MultiColumnHeaderState(columns);
			return state;
        }

#region Sort

        /// <summary>
        /// 排序选项
        /// </summary>
        private LoadTreeSortOptions[] _sortOptions = new []
        {
            LoadTreeSortOptions.No,
            LoadTreeSortOptions.Asset,
            LoadTreeSortOptions.AssetType,
            LoadTreeSortOptions.Extension,
            LoadTreeSortOptions.From,
            LoadTreeSortOptions.Async,
            LoadTreeSortOptions.ReferenceCount,
            LoadTreeSortOptions.Size,
            LoadTreeSortOptions.MemorySize,
            LoadTreeSortOptions.CostTime,
            LoadTreeSortOptions.LoadTime
        };

        /// <summary>
		/// 根据列排序
		/// </summary>
		/// <param name="iHeaderColumns">头部列</param>
		/// <param name="iRoot">根节点</param>
		protected override void SortByColumns(MultiColumnHeader iHeaderColumns, TreeViewItem iRoot)
		{
			if(null == iHeaderColumns || null == iRoot) return;
            var sortedColumns = iHeaderColumns.state.sortedColumns;
            if (0 >= sortedColumns.Length) return;

            var rows = iRoot.children.Cast<TreeViewRow<LoadBranch>>();
            var orderedQuery = InitialOrder (iHeaderColumns, rows, sortedColumns);
            if(null == orderedQuery) return;
            
            for (var idx = 0; idx < sortedColumns.Length; ++idx)
            {
                var sortOption = _sortOptions[sortedColumns[idx]];
                var ascending = iHeaderColumns.IsSortedAscending(sortedColumns[idx]);
                switch (sortOption)
                {
                    case LoadTreeSortOptions.Asset:
                    {
	                    foreach (var it in orderedQuery)
	                    {
		                    it.SortChildren(iC => iC.Data.Caller, ascending);
	                    }
                    }
                        break;
	                case LoadTreeSortOptions.AssetType:
	                {
		                foreach (var it in orderedQuery)
		                {
			                it.SortChildren(iC => $"{iC.Data.AssetType}", ascending);
		                }
	                }
                        break;
	                case LoadTreeSortOptions.Extension:
	                {
		                foreach (var it in orderedQuery)
		                {
			                it.SortChildren(iC => iC.Data.Extension, ascending);
		                }
	                }
                        break;
	                case LoadTreeSortOptions.From:
	                {
		                foreach (var it in orderedQuery)
		                {
			                it.SortChildren(iC => iC.Data.From, ascending);
		                }
	                }
                        break;
	                case LoadTreeSortOptions.Async:
	                {
		                foreach (var it in orderedQuery)
		                {
			                it.SortChildren(iC => iC.Data.Async, ascending);
		                }
	                }
                        break;
	                case LoadTreeSortOptions.ReferenceCount:
	                {
		                foreach (var it in orderedQuery)
		                {
			                it.SortChildren(iC => iC.Data.ReferenceCount, ascending);
		                }
	                }
	                    break;
	                case LoadTreeSortOptions.Size:
	                {
		                foreach (var it in orderedQuery)
		                {
			                it.SortChildren(iC => iC.Data.Size, ascending);
		                }
	                }
                        break;
                    case LoadTreeSortOptions.MemorySize:
                    {
	                    foreach (var it in orderedQuery)
	                    {
		                    it.SortChildren(iC => iC.Data.MemorySize, ascending);
	                    }
                    }
                        break;
	                case LoadTreeSortOptions.CostTime:
	                {
		                foreach (var it in orderedQuery)
		                {
			                it.SortChildren(iC => iC.Data.CoolTime, ascending);
		                }
	                }
                        break;
	                case LoadTreeSortOptions.LoadTime:
	                {
		                foreach (var it in orderedQuery)
		                {
			                it.SortChildren(iC => iC.Data.LoadTime, ascending);
		                }
	                }
                        break;
                    default:
	                    throw new TableTreeUnknownSortOptionsException($"Unknown Sort Option:{sortOption}");
	                    break;
                }
            }

            iRoot.children = orderedQuery.Cast<TreeViewItem> ().ToList ();
		}
        
        /// <summary>
        /// 初始化排序
        /// </summary>
        /// <param name="iHeaderColumns">头部列</param>
        /// <param name="iRows">行列表</param>
        /// <param name="iColumnIndexes">列索引列表</param>
        /// <returns>可排序的列表</returns>
        protected override IOrderedEnumerable<TreeViewRow<LoadBranch>> InitialOrder(
            MultiColumnHeader iHeaderColumns, IEnumerable<TreeViewRow<LoadBranch>> iRows, 
            int[] iColumnIndexes)
        {
            var sortColIndex = _sortOptions[iColumnIndexes[0]];
            var ascending = iHeaderColumns.IsSortedAscending(iColumnIndexes[0]);

            switch (sortColIndex)
            {
                case LoadTreeSortOptions.Asset:
                {
                    if (ascending)
                    {
	                    return iRows
                            .OrderBy(iL => iL.Data.AssetKey)
                            .ThenBy(iL => iL.Data.Caller);       
                    }

                    return iRows
                        .OrderByDescending(iL => iL.Data.AssetKey)
                        .ThenByDescending(iL => iL.Data.Caller);
                }
                case LoadTreeSortOptions.AssetType:
                    return iRows.Order(iL => $"{iL.Data.AssetType}", ascending);
                case LoadTreeSortOptions.Extension:
                    return iRows.Order(iL => iL.Data.Extension, ascending);
                case LoadTreeSortOptions.From:
                    return iRows.Order(iL => iL.Data.From, ascending);
                case LoadTreeSortOptions.Async:
                    return iRows.Order(iL => iL.Data.Async, ascending);
                case LoadTreeSortOptions.ReferenceCount:
	                return iRows.Order(iL => iL.Data.ReferenceCount, ascending);
                case LoadTreeSortOptions.Size:
                    return iRows.Order(iL => iL.Data.Size, ascending);
                case LoadTreeSortOptions.MemorySize:
                    //return iRows.Order(iL => iL.Data.MemorySize, ascending);
                    return iRows.Order(iL => 0, ascending);;
                case LoadTreeSortOptions.CostTime:
                    return iRows.Order(iL => iL.Data.CostTime, ascending);
                case LoadTreeSortOptions.LoadTime:
                    return iRows.Order(iL => iL.Data.LoadTime, ascending);
                default:
                    throw new TableTreeUnknownColumnException($"Unknown Sort Col Index:{sortColIndex}");
                    break;
            }
        }
        
#endregion

#endregion

#region Draw
        
        /// <summary>
        /// 绘制窗体Body
        /// </summary>
        /// <param name="iRect">制矩形范围</param>
        /// <param name="iEvent">Event</param>
        /// <returns>制矩形范围</returns>
        protected override Rect DrawWinBody(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;

            var searchBarRect = displayRect;
            searchBarRect.height = SingleLineHeight;
            if (Searchable)
            {
                TableTree.SearchKey = SearchBar.OnGUI (searchBarRect, TableTree.SearchKey);
            }

            var treeRect = searchBarRect;
            treeRect.yMin = searchBarRect.yMax + VerticalSpacing;
            treeRect.yMax = displayRect.yMax;
            TableTree.DrawSelf(treeRect, iEvent);
		            
            return displayRect;
        }

        private static string TXT_NONE = "-";
        private static string TXT_ASYNC = "异步";
        private static string TXT_SYNC = "同步";
        
        /// <summary>
        /// 绘制TableTree的列
        /// </summary>
        /// <param name="iRect">绘制矩形范围</param>
        /// <param name="iBranch">加载信息</param>
        /// <param name="iRowIndex">行索引</param>
        /// <param name="iColumnIndex">列索引</param>
        protected override void DrawTableTreeColumn(Rect iRect, LoadBranch iBranch, int iRowIndex, int iColumnIndex)
        {
	        var column = (LoadTreeColumns)iColumnIndex;
	        switch (column)
	        {
		        case LoadTreeColumns.No:
		        {
			        GUI.Label(iRect, $"{iRowIndex+1}", GuiExHelper.MiddleCenterLabel);
		        }
			        break;
		        case LoadTreeColumns.Asset:
		        {
			        if (iBranch.IsCaller)
			        {
				        GUI.Label(iRect, iBranch.Caller, GuiExHelper.MiddleLeftLabel);
			        }
			        else
			        {
				        var assetCaption = UtilsGUIEx.CreateGuiContentByPathOfAsset(iBranch.AssetKey, iBranch.AssetKey, true, false);
				        GUI.Label(iRect, assetCaption, GuiExHelper.MiddleLeftLabel);
			        }
		        }
			        break;
		        case LoadTreeColumns.AssetType:
		        {
			        var assetTypeTxt = iBranch.IsCaller ? TXT_NONE : $"{iBranch.AssetType}";
			        GUI.Label(iRect, assetTypeTxt, GuiExHelper.MiddleCenterLabel);
		        }
			        break;
		        case LoadTreeColumns.Extension:
		        {
			        var extensionTxt = iBranch.IsCaller ? TXT_NONE : iBranch.Extension;
			        GUI.Label(iRect, extensionTxt, GuiExHelper.MiddleCenterLabel);
		        }
			        break;
		        case LoadTreeColumns.From:
		        {
			        GUI.Label(iRect, iBranch.From, GuiExHelper.MiddleCenterLabel);
		        }
			        break;
		        case LoadTreeColumns.Async:
		        {
			        var asyncTxt = iBranch.Async ? TXT_ASYNC : TXT_SYNC;
			        GUI.Label(iRect, asyncTxt, GuiExHelper.MiddleCenterLabel);
		        }
			        break;
		        case LoadTreeColumns.Size:
		        {
			        if (iBranch.IsCaller)
			        {
				        GUI.Label(iRect, TXT_NONE, GuiExHelper.MiddleCenterLabel);
			        }
			        else
			        {
				        var sizeDisplayTxt = UtilsMath.GetDataDisplaySize(iBranch.Size, false);
				        GUI.Label(iRect, sizeDisplayTxt, GuiExHelper.MiddleCenterLabel);
			        }
		        }
			        break;
		        case LoadTreeColumns.MemorySize:
		        {
			        if (iBranch.IsCaller)
			        {
				        var sizeDisplayRect = UtilsMath.GetDataDisplaySize(iBranch.MemorySize, false);
				        GUI.Label(iRect, sizeDisplayRect, GuiExHelper.MiddleCenterLabel);
			        }
			        else
			        {
				        GUI.Label(iRect, TXT_NONE, GuiExHelper.MiddleCenterLabel);
			        }
		        }
			        break;
		        case LoadTreeColumns.ReferenceCount:
		        {
			        var asyncTxt = iBranch.IsCaller ? TXT_NONE : $"{iBranch.ReferenceCount}";
			        GUI.Label(iRect, asyncTxt, GuiExHelper.MiddleCenterLabel);
		        }
			        break;
		        case LoadTreeColumns.CostTime:
		        {
			        var costTimeTxt = UtilsTime.ConvertToDisplayTime(iBranch.CostTime);
			        GUI.Label(iRect, costTimeTxt, GuiExHelper.MiddleCenterLabel);
		        }
			        break;
		        case LoadTreeColumns.LoadTime:
		        {
			        var loadTimeTxt = UtilsTime.ConvertByFormat(iBranch.LoadTime);
			        GUI.Label(iRect, loadTimeTxt, GuiExHelper.MiddleCenterLabel);
		        }
			        break;
				default:
					break;
	        }
        }

#endregion
        
    }
}
